﻿/**
 *
 * AS3 SWX Connecter
 * Copyright © 2008 Omi Chowdhury. http://mangosix.co.uk
 * Part of the SWX (SWF Data Exchange Format) project. http://swxformat.org
 *
 * Released under the open source MIT license.
 * http://opensource.org/licenses/mit-license.php
 *  
 * This mimics the AS2 SWX API and relays calls to an AVM1 connecter
 * file (connecter.swf) via a LocalConnection (lcSC). Results are sent 
 * back from the connecter via a different LocalConnection (lcCS). 
 *
 * Initial LocalConnections (ilcSC and ilcCS) are used to communicate a
 * randomised LocalConnection id so multiple instances of the AS3 SWX
 * Connecter can run concurrently.
 *
 * You can specify the location of the connecter.swf file in the constructor.
 *
 * Please see AS3_add_numbers_as_lib.fla in the examples folder for sample usage
 *
 */
package com.mangosix {
	import flash.display.Loader;
	import flash.events.*;
	import flash.net.LocalConnection;
	import flash.net.URLRequest;
	import flash.net.URLVariables;
	
	public class SWX {
		// Vars
		private var ilcSC:LocalConnection = new LocalConnection(); // Initial LC for SWX > Connecter
		private var lcSC:LocalConnection = new LocalConnection(); //Normal LC for SWX > Connecter
		private var ilcSCid:String = "_lcSC"; // Initial LC id 
		private var rlcSCid:String = ""; // Normal LC id
		
		private var ilcCS:LocalConnection = new LocalConnection(); // Initial LC for Connecter > SWX		
		private var lcCS:LocalConnection = new LocalConnection(); // Normal LC for Connecter > SWX		
		private var ilcCSid:String = "_lcCS"; // Initial LC id
		private var rlcCSid:String = ""; // Normal LC id
				
		private var loader:Loader = new Loader(); //Loads connecter.swf
		private var connecterLoaded:Boolean = false;
		private var SWXvars:Object = {gateway: "", encoding: "POST", debug: false, timeout: 30};
		private var calls:Array = new Array(); //call queue
		private var busy:Boolean = true; //SWX is active?
		
		//
		// Instance methods
		//
		public function SWX(connecterLocation:String = "connecter.swf") {
			//Load up the connecter
			var connecterRequest:URLRequest = new URLRequest(connecterLocation);
			loader.load(connecterRequest);
			
			//Set up our Initial LocalConnection, ready for the new id
			ilcCS.allowDomain("*");
			ilcCS.connect(ilcCSid);
			ilcCS.client = this;
		}
		
		public function set gateway(varValue:String):void {
			setSWXVar("gateway", varValue);
		}
		
		public function set encoding(varValue:String):void {
			setSWXVar("encoding", varValue);
		}
		
		public function set timeout(varValue:int):void {
			setSWXVar("timeout", varValue);
		}
		
		public function set debug(varValue:Boolean):void {
			setSWXVar("debug", varValue);
		}
		
		public function call (callDetails:Object):void {
			//Add it to the call queue
			calls.push(callDetails);
			//Call next in queue if no one else going to
			if(!busy) {
				_call(calls[0]);
			}
		}
		private function _call(callDetails:Object):void {
			//SWX production line is now in full motion
			busy = true;
			//Tell connecter to SWX.call()
			lcSC.send(rlcSCid, "call", callDetails);
		}
		
		public function cancelAllCalls():void {
			//Tell connecter to SWX.cancelAllCalls()
			lcSC.send(rlcSCid, "cancelAllCalls");
		}
		
		//
		// Callback methods
		//
		
		public function onConnecterLoaded(newlcCSid:String):void {
			//Set up Normal lcCS
			lcCS.allowDomain("*");
			lcCS.connect(newlcCSid);
			lcCS.client = this;
			
			//Close Initial lcCS
			ilcCS.close();
			
			//Set new lcSCid
			var now:Date = new Date();
			rlcSCid = "_lcSC" + String(now.getTime() * Math.random());
			
			//Tell Connecter to use it
			ilcSC.send(ilcSCid, "onSWXReady", rlcSCid);
		}
		
		public function go():void {
			//GO GO GO
			connecterLoaded = true;
			busy = false;
			
			//Update all the SWXvars
			for(var i:String in SWXvars) {
				lcSC.send(rlcSCid, "setVar", i, SWXvars[i]);
			}
			
			//If there is a call to make
			if(calls[0] != undefined) {
				_call(calls[0]);//Do so
			}
		}
		
		//Handles all callbacks from SWX (result, timeout, fault, progress)
		public function SWXhandler(ev:Object):void {
			//SWX uses "load" internally, but "result" for the eventHandler so change it
			if(ev.type == "load") {
				ev.type = "result";
			}
			//Has user supplied a callback?
			if(calls[0][ev.type] != undefined) {
				//Is it [this, callbackFunc]
				if(calls[0][ev.type] is Array) {
					calls[0][ev.type][1](ev);
				//or just callbackFunc
				} else if(calls[0][ev.type] is Function) {
					calls[0][ev.type](ev);
				}
			}
			
			//All other events signal end of call
			if(ev.type != "progress") {
				doNextCall();
			}
		}
		
		//
		// Private methods
		//
		
		private function doNextCall():void {
			//Move onto next call
			calls.shift();
			
			if(calls[0] == undefined) {//There are no other calls in the queue
				busy = false; //Take a break
			} else {
				_call(calls[0]);
			}
		}
		
		private function setSWXVar(type:String, varValue:*):void {
			//Set it here
			SWXvars[type] = varValue;
			
			//Set it in connecter
			if(connecterLoaded) {
				lcSC.send(rlcSCid, "setVar", type, varValue);
			}
		}
	}
}